/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://gitee.com/newgolo/embedme.git
 * Copyright 2014~2020 @ ShenZhen ,China
*******************************************************************************/
#include "BaseType.h"
#include "Tracer.h"
#include "FileUtil.h"
#include "JSONData.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

namespace libembx{
using namespace std;
using namespace libemb;
/**
 *  @brief  JSONNode构造函数
 *  @param  none
 *  @return none
 *  @note   JSONNode代表一个用key:value表示的JSON子结点
 */
JSONNode::JSONNode():
m_object(NULL),
m_name("")
{
}

/**
 *  @brief  JSONNode拷贝构造函数
 *  @param  none
 *  @return none
 *  @note   用于值传递用,浅拷贝(不拷贝cJSON里的数据)
 */
JSONNode::JSONNode(const JSONNode& node)
{
    this->m_object = node.m_object;
    this->m_name = node.m_name;
}

/**
 *  @brief  JSONNode析构函数
 *  @param  none
 *  @return none
 */
JSONNode::~JSONNode()
{
	m_appendNodes.clear();
}

/**
 *  @brief  返回串行化后的字符串
 *  @param  bool fmt 是否格式化
 *  @return 结点字符串
 *  @note   none
 */
std::string JSONNode::serialize(bool fmt)
{
    char* out=NULL;
    if (fmt)
    {
        out = cJSON_Print(m_object);
    }
    else
    {
        out = cJSON_PrintUnformatted(m_object);
    }
    if (out!=NULL)
    {
        std::string jsonString = std::string(out);
        free(out);
        return jsonString;
    }
    return "";
}

/**
 *  @brief  判断是否存在nodeName结点
 *  @param  nodeName 结点名称字符串
 *  @return 存在返回true,不存在返回false
 *  @note   none
 */
bool JSONNode::hasSubNode(const std::string nodeName)
{
    if(NULL==cJSON_GetObjectItem(m_object, CSTR(nodeName)))
    {
        return false;
    }
    return true;
}

/**
 *  @brief  判断结点是否是NULL结点
 *  @param  none
 *  @return false or true
 *  @note   none
 */
bool JSONNode::isNullNode()
{
    if (!m_object)
    {
        return false;
    }
    return (m_object->type==cJSON_NULL)?true:false;
}
/**
 *  @brief  判断结点是否是数组型结点
 *  @param  none
 *  @return false or true
 *  @note   none
 */
bool JSONNode::isArrayNode()
{
    if (!m_object)
    {
        return false;
    }
    return (m_object->type==cJSON_Array)?true:false;
}

/**
 *  @brief  根据index获取数组的大小
 *  @param  none
 *  @return 返回数组结点里的元素(结点)个数
 *  @note   none
 */
int JSONNode::getArraySize()
{
    JSONNode node;
    if (!m_object)
    {
        return 0;
    }
    return cJSON_GetArraySize(m_object);
}

/**
 *  @brief  根据结点名称nodeName获取子结点
 *  @param  nodeName 结点名称字符串
 *  @return 返回结点对象
 *  @note   none
 */
JSONNode JSONNode::operator[](const std::string nodeName)
{
    JSONNode node;
    if (!m_object||
        nodeName.empty())
    {
        return node;
    }
    node.m_object = cJSON_GetObjectItem(m_object, CSTR(nodeName));
    node.m_name = nodeName;
    return node;
}

/**
 *  @brief  根据index获取数组结点里的元素结点
 *  @param  index 索引值
 *  @return 返回index对应的数组元素
 *  @note   数组元素也是一个结点,因为数组里可以包含任意类型的结点
 */
JSONNode JSONNode::operator[](int index)
{
    JSONNode node;
    if (!m_object)
    {
        return node;
    }
    node.m_object = cJSON_GetArrayItem(m_object, index);
    node.m_name = "";
    return node;
}

/**
 *  @brief  返回结点的布尔值
 *  @param  none
 *  @return false or true
 *  @note   none
 */
bool JSONNode::toBool()
{
    if ((!m_object) ||
        (m_object->type!=cJSON_False &&
         m_object->type!=cJSON_True))
    {
        return false;
    }
    return (m_object->type==cJSON_True)?true:false;
}
/**
 *  @brief  返回结点的整形值
 *  @param  none
 *  @return int
 *  @note   none
 */
int JSONNode::toInt()
{
    if (!m_object || m_object->type!=cJSON_Number)
    {
        return 0;
    }
    return m_object->valueint;
}
/**
 *  @brief  返回结点的浮点值
 *  @param  none
 *  @return double
 *  @note   none
 */
double JSONNode::toDouble()
{
    if (!m_object || m_object->type!=cJSON_Number)
    {
        return 0;
    }
    return m_object->valuedouble;
}
/**
 *  @brief  返回结点的字符串值
 *  @param  none
 *  @return 返回字符串
 *  @note   none
 */
std::string JSONNode::toString()
{
    if (!m_object || m_object->type!=cJSON_String)
    {
        return "";
    }
    char* str= m_object->valuestring;
    if (!str)
    {
        return "";
    }
    return std::string(str);
}

JSONNode JSONNode::toNode()
{
    JSONNode node;
    if (!m_object || m_object->type!=cJSON_Object)
    {
        return node;
    }
    node.m_object = m_object;
    node.m_name = "";
    return node;
}

bool JSONNode::setValue(bool value)
{
    if (!m_object ||
        (m_object->type!=cJSON_True &&
        m_object->type!=cJSON_False))
    {
        return false;
    }
    m_object->type = value?cJSON_True:cJSON_False;
    return true;
}

bool JSONNode::setValue(int value)
{
    if (!m_object ||
        m_object->type!=cJSON_Number)
    {;
        return false;
    }
    cJSON_SetNumberValue(m_object,value);
    return true;
}

bool JSONNode::setValue(double value)
{
    if (!m_object || 
        m_object->type!=cJSON_Number)
    {
        return false;
    }
    cJSON_SetNumberValue(m_object,value);
    return true;
}

bool JSONNode::setValue(const char* value)
{
    if (!m_object || 
        m_object->type!=cJSON_String)
    {
        return false;
    }
    char* newString = (char*)malloc(strlen(value)+1);
    if (!newString) 
    {
        return false;
    }
    strcpy(newString,value);
    free(m_object->valuestring);
    m_object->valuestring = newString;
    return true;
}

/**
 *  @brief  加入布尔值子结点
 *  @param  nodeName 名称字串
 *  @return 成功返回true,失败返回false
 *  @note   当JSON数据为数组格式时,nodeName可省略
 */
bool JSONNode::addSubNode(bool value,const std::string nodeName)
{
    if (!m_object)
    {
        return addNullNode(nodeName);
    }
    cJSON_AddItemToObject(m_object, CSTR(nodeName), cJSON_CreateBool((int)value));
    return true;
}
/**
 *  @brief  加入数字值子结点
 *  @param  nodeName 名称字串
 *  @param  value 整数或浮点数
 *  @return 成功返回true,失败返回false
 *  @note   当JSON数据为数组格式时,nodeName可省略
 */
bool JSONNode::addSubNode(int value,const std::string nodeName)
{
    if (!m_object)
    {
        return addNullNode(nodeName);
    }
    cJSON_AddItemToObject(m_object, CSTR(nodeName), cJSON_CreateNumber(value));
    return true;
}

/**
 *  @brief  加入数字值子结点
 *  @param  nodeName 名称字串
 *  @param  value 整数或浮点数
 *  @return 成功返回true,失败返回false
 *  @note   当JSON数据为数组格式时,nodeName可省略
 */
bool JSONNode::addSubNode(double value,const std::string nodeName)
{
    if (!m_object)
    {
        return addNullNode(nodeName);
    }
    cJSON_AddItemToObject(m_object, CSTR(nodeName), cJSON_CreateNumber(value));
    return true;
}
/**
 *  @brief  加入字符串子结点
 *  @param  nodeName 名称字串
 *  @return 成功返回true,失败返回false
 *  @note   当JSON数据为数组格式时,nodeName可省略
 */
bool JSONNode::addSubNode(const char* value,const std::string nodeName)
{
    if (!m_object)
    {
        return addNullNode(nodeName);
    }
    cJSON_AddItemToObject(m_object, CSTR(nodeName), cJSON_CreateString(value));
    return true;
}
/**
 *  @brief  加入JSON对象子结点
 *  @param  nodeName 名称字串
 *  @return 成功返回true,失败返回false
 *  @note   当JSON数据为数组格式时,nodeName可省略
 */
bool JSONNode::addSubNode(std::shared_ptr<JSONNode> node,const std::string nodeName)
{
    if (!m_object || !node)
    {
        return addNullNode(nodeName);
    }
    cJSON_AddItemToObject(m_object, CSTR(nodeName),cJSON_Duplicate(node->m_object,1));
	m_appendNodes.push_back(node);
    return true;
}

/**
 *  @brief  加入NULL子结点
 *  @param  nodeName 名称字串
 *  @return 成功返回true,失败返回false
 *  @note   当JSON数据为数组格式时,nodeName可省略
 */
bool JSONNode::addNullNode(const std::string nodeName)
{
    if (!m_object)
    {
        return false;
    }
    cJSON_AddItemToObject(m_object, CSTR(nodeName), cJSON_CreateNull());
    return true;
}

/**
 *  @brief  JSONData构造函数
 *  @param  none
 *  @return none
 *  @note   JSONData有两种形式,一种是对象形式:形如"{key:value,...}",用大括号
            将所有子结点包围.另一种是更简化的数组形式:形如"[{...},{...}]",用
            中括号[]将同一类型的子结点包围,数组中可以包含同一类型的对象.
            JSONData的根结点就是它本身,其他的都视为子结点。
 */
JSONData::JSONData()
{
}

JSONData::~JSONData()
{
    deleteAllNodes();
}
/**
 *  @brief  初始化JSONData为对象形式
 *  @param  none
 *  @return 成功返回根结点,失败返回NULL
 *  \note   none
 */
std::shared_ptr<JSONNode> JSONData::initWithObjectFormat()
{
    deleteAllNodes();
    m_rootNode = std::make_shared<JSONNode>();
    m_rootNode->m_object = cJSON_CreateObject();
    return m_rootNode;
}
/**
 *  @brief  初始化JSONData为数组形式
 *  @param  none
 *  @return 成功返回根结点,失败返回NULL
 *  \note   none
 */
std::shared_ptr<JSONNode> JSONData::initWithArrayFormat()
{
    deleteAllNodes();
    m_rootNode = std::make_shared<JSONNode>();
    m_rootNode->m_object = cJSON_CreateArray();
    return m_rootNode;
}
/**
 *  @brief  读取JSON字符串进行初始化
 *  @param  none
 *  @return 成功返回根结点,失败返回NULL
 *  \note   none
 */
std::shared_ptr<JSONNode> JSONData::initWithDataString(const char* jdata)
{
    deleteAllNodes();
    m_rootNode = std::make_shared<JSONNode>();	
	m_rootNode->m_object = cJSON_Parse(jdata);
	if (!m_rootNode->m_object)
    {
        TRACE_ERR_CLASS("Error before: [%s],json string:[%s]\n",cJSON_GetErrorPtr(),jdata);
        return NULL;
    }
    return m_rootNode;
}

/**
 *  @brief  获取根节点
 *  @param  none
 *  @return 返回根结点
 *  \note   none
 */
std::shared_ptr<JSONNode> JSONData::getRootNode()
{
    return m_rootNode;
}
/**
 *  @brief  写入JSON数据到文件中
 *  @param  none
 *  @return 成功返回true,失败返回false
 *  \note   none
 */
bool JSONData::saveAsFile(const std::string fileName,bool fmt)
{
    bool rc=false;
    File file;
    if(file.open(CSTR(fileName),IO_MODE_REWR_ORNEW))
    {
        if (m_rootNode)
        {
            char* out=NULL;
            if (fmt)
            {
                out=cJSON_Print(m_rootNode->m_object);
            }
            else
            {
                out=cJSON_PrintUnformatted(m_rootNode->m_object);
            }
            if (out!=NULL)
            {
                int len = strlen(out);
                if (file.writeData(out,len)!=len)
                {
                    TRACE_ERR_CLASS("write file error:%s\n",CSTR(fileName));
                }
    	        free(out);
            }
            rc = true;
        }
    }
    return rc;
}

/**
 *  @brief  串行化JSONData成字符串
 *  @param  none
 *  @return 成功返回STATUS_OK,失败返回STATUS_ERROR
 *  \note   none
 */
std::string JSONData::serialize(bool fmt)
{
    char* out=NULL;
    if (fmt)
    {
        out=cJSON_Print(m_rootNode->m_object);
    }
    else
    {
        out=cJSON_PrintUnformatted(m_rootNode->m_object);
    }
    if (out!=NULL)
    {
        std::string jsonString=string(out);
        free(out);
        return jsonString;
    }
    return "";
}

bool JSONData::deleteAllNodes()
{
    if (m_rootNode)
    {
        if (m_rootNode->m_object!=NULL)
        {
            /* 删除根结点下的所有结点 */
            cJSON_Delete(m_rootNode->m_object);
        }
    }
    return true;
}
}
